﻿using System.Globalization;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Reflection;
using Devonline.Communication.Messages;
using Devonline.Entity;
using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.DynamicLinq;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;

namespace Devonline.AspNetCore;

/// <summary>
/// 公共数据处理服务
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
/// <typeparam name="TEntitySet">业务数据类型</typeparam>
/// <typeparam name="TKey">键类型</typeparam>
public class DataService<TDbContext, TEntitySet, TKey> :
    ServiceBase<TDbContext, TKey>,
    IDataService<TDbContext, TEntitySet, TKey>
    where TDbContext : DbContext
    where TEntitySet : class, IEntitySet<TKey>
    where TKey : IConvertible
{
    protected readonly IMessageCommunicator _communicator;
    protected readonly DbSet<TEntitySet> _dbSet;
    protected readonly Type _type;
    protected readonly string _typeName;
    protected readonly bool _localCache;

    /// <summary>
    /// 构造方法
    /// </summary>
    /// <param name="logger">日志</param>
    /// <param name="context">数据库上下文</param>
    /// <param name="httpContextAccessor">Http上下文</param>
    /// <param name="cache">缓存</param>
    /// <param name="appSetting">配置</param>
    public DataService(
        TDbContext context,
        ILogger<DataService<TDbContext, TEntitySet, TKey>> logger,
        IDistributedCache cache,
        IHttpContextAccessor httpContextAccessor,
        IMessageCommunicator communicator,
        AppSetting appSetting
        ) : base(context, logger, cache, httpContextAccessor, appSetting)
    {
        _communicator = communicator;
        _dbSet = _context.Set<TEntitySet>();
        _type = typeof(TEntitySet);
        _typeName = typeof(TEntitySet).GetDisplayName();
        var cacheAttribute = _type.GetCustomAttribute<CacheableAttribute>();
        if (cacheAttribute == null)
        {
            _enableCache = false;
            _localCache = false;
        }
        else
        {
            _localCache = cacheAttribute.LocalCache;
        }

        AdapterConfig = GetAdapterConfig<TEntitySet>();
    }

    #region 数据查询方法
    /// <summary>
    /// 统一数据源查询入口, 可缓存数据源, 仅返回当前类型引用
    /// </summary>
    /// <returns></returns>
    public virtual IQueryable<TEntitySet> GetQueryable()
    {
        if (_enableCache)
        {
            var cacheKey = AppSettings.CACHE_DATA + _type.Name.ToUpper(CultureInfo.CurrentCulture);
            var entitySets = _cache.GetValue<IEnumerable<TEntitySet>>(cacheKey);
            if (entitySets == null)
            {
                _logger.LogInformation("{type} have no cache data, will query and cached", _typeName);
                entitySets = _dbSet.ToHashSet();
                _cache.SetValue(cacheKey, entitySets);
            }

            return entitySets.AsQueryable();
        }

        _logger.LogDebug("The user {user} query {typeName}", UserName, _typeName);
        return _dbSet;
    }
    /// <summary>
    /// 非注入类型 TEntity 统一数据源查询入口, 可缓存数据源, 可返回泛型类型指定的任意类型引用
    /// </summary>
    /// <param name="predicate">过滤条件</param>
    /// <returns></returns>
    public virtual IQueryable<TEntitySet> GetQueryable(Expression<Func<TEntitySet, bool>> predicate) => GetQueryable().Where(predicate);
    /// <summary>
    /// 根据 id 获取对象
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public virtual async Task<TEntitySet?> GetAsync(TKey id) => await GetQueryable().FirstOrDefaultAsync(x => x.Id.Equals(id));
    /// <summary>
    /// 从 QueryOptions 和上下文自动获取查询表达式的内容并执行查询返回分页的结果
    /// 暂不支持 orderby, select 和 expand 表达式
    /// </summary>
    /// <returns></returns>
    public virtual async Task<PagedResult> GetPagedResultAsync() => await GetPagedResultAsync<TEntitySet>();
    /// <summary>
    /// 适用于新增时判断对象是否存在, 存在则抛出异常
    /// </summary>
    /// <param name="id">业务数据编号</param>
    /// <returns></returns>
    /// <exception cref="BadHttpRequestException"></exception>
    public virtual async Task ThrowIfExistAsync(TKey? id)
    {
        if ((!(id == null || id.Equals(default))) && await GetQueryable().AnyAsync(x => x.Id.Equals(id)))
        {
            throw new BadHttpRequestException($"{_typeName} 中当前记录已存在!");
        }
    }
    /// <summary>
    /// 适用于更新时判断当前对象是否存在, 存在则返回按 Id 查询的结果, 不存在则抛出异常
    /// </summary>
    /// <param name="id">业务数据主键</param>
    /// <returns></returns>
    /// <exception cref="BadHttpRequestException"></exception>
    public virtual async Task<TEntitySet> GetIfExistAsync(TKey id)
    {
        var entitySet = await GetAsync(id);
        if (entitySet == null)
        {
            throw new BadHttpRequestException($"{_typeName} 中当前记录不存在!");
        }

        return entitySet;
    }
    /// <summary>
    /// 获取业务数据的集合成员, 成员是附加信息, 附件及特定类型的附属集合
    /// </summary>
    /// <typeparam name="TElement">附加信息, 附件或附属集合的类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    public virtual IEnumerable<TElement>? GetCollectionMembers<TElement>(TEntitySet entitySet) where TElement : class, IEntitySet<TKey> => base.GetCollectionMembers<TEntitySet, TElement>(entitySet);
    #endregion

    #region 数据操作方法
    /// <summary>
    /// 新增阶段判断满足条件的数据是否存在, 存在则抛出异常, 不存在则执行基类预定义赋值操作
    /// </summary>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    /// <exception cref="BadHttpRequestException"></exception>
    public virtual async Task UniqueAsync(TEntitySet entitySet)
    {
        var propertyInfos = _type.GetProperties().Where(x => x.HasAttribute<UniqueAttribute>());
        if (propertyInfos.IsNotNullOrEmpty())
        {
            var index = 0;
            var keys = new List<string>();
            var values = new List<object>();
            var messages = new List<string>();

            if (!(entitySet.Id == null || entitySet.Id.Equals(default)))
            {
                keys.Add($"{nameof(entitySet.Id)} != @{index++}");
                values.Add($"{entitySet.Id}");
            }

            foreach (var propertyInfo in propertyInfos)
            {
                var value = propertyInfo.GetValue(entitySet);
                keys.Add($"{propertyInfo.Name} == @{index++}");
                values.Add($"{value}");
                messages.Add($"<{propertyInfo.GetDisplayName()}> = {value}");
            }

            var predicate = string.Join(" and ", keys);
            var exist = await GetQueryable<TEntitySet>().AnyAsync(predicate, values.ToArray());
            if (exist)
            {
                throw new BadHttpRequestException($"{_typeName} 中 {messages.ToString<string>()} 的记录已经存在!");
            }
        }
    }
    /// <summary>
    /// 单个数据对象的新增, 自动验证重复
    /// </summary>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> AddAsync(TEntitySet entitySet)
    {
        _logger.LogDebug("The user {user} will add {typeName}, the content is: " + entitySet, UserName, _typeName);

        await base.AddAsync(entitySet);
        await SaveChangesAsync();
        return entitySet;
    }
    /// <summary>
    /// 批量新增, 自动验证重复
    /// </summary>
    /// <param name="entitySets">业务数据</param>
    /// <returns></returns>
    public virtual async Task<IEnumerable<TEntitySet>> AddsAsync(IEnumerable<TEntitySet> entitySets)
    {
        if (!entitySets.Any())
        {
            return entitySets;
        }

        var content = new List<string>();
        foreach (var entitySet in entitySets)
        {
            content.Add(entitySet.ToKeyValuePairs().ToString(AppSettings.DEFAULT_OUTER_SPLITER, AppSettings.DEFAULT_INNER_SPLITER));
        }

        _logger.LogDebug("The user {user} will adds {typeName}, the content is: " + string.Join("; ", content), UserName, _typeName);

        foreach (var entitySet in entitySets)
        {
            await base.AddAsync(entitySet);
        }

        await SaveChangesAsync();
        return entitySets;
    }
    /// <summary>
    /// 更新阶段判断满足条件的数据是否存在, 存在则抛出异常, 不存在则执行基类预定义赋值操作, 自动验证重复
    /// </summary>
    /// <param name="entitySet">业务数据</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> UpdateAsync(TEntitySet entitySet, bool isLogical = false)
    {
        _logger.LogDebug("The user {user} will {isLogical} update {typeName}, the content is: " + entitySet, UserName, GetLogicalString(isLogical), _typeName);

        await base.UpdateAsync(entitySet, isLogical);
        await SaveChangesAsync(isLogical);
        return entitySet;
    }
    /// <summary>
    /// 批量新增或修改数据对象模型到当前上下文, 但不提交
    /// </summary>
    /// <param name="entitySets">业务数据</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task<IEnumerable<TEntitySet>> AddsOrUpdatesAsync(IEnumerable<TEntitySet> entitySets, bool isLogical = false)
    {
        if (!entitySets.Any())
        {
            return entitySets;
        }

        var content = new List<string>();
        foreach (var entitySet in entitySets)
        {
            content.Add(entitySet.ToKeyValuePairs().ToString(AppSettings.DEFAULT_OUTER_SPLITER, AppSettings.DEFAULT_INNER_SPLITER));
        }

        _logger.LogDebug("The user {user} will {isLogical} adds or updates {typeName}, the content is: " + content, UserName, GetLogicalString(isLogical), _typeName);
        var list = new List<TEntitySet>();
        var ids = entitySets.Select(x => x.Id).Distinct();
        var entities = await GetQueryable().Where(x => ids.Contains(x.Id)).ToListAsync();
        foreach (var entitySet in entitySets)
        {
            await UniqueAsync(entitySet);
            var entity = entities.FirstOrDefault(x => x.Id.Equals(entitySet.Id));
            if (entity == null)
            {
                Create(entitySet);
                Update(entitySet);
                Detach(entitySet);
                list.Add(entitySet);
                await _dbSet.AddAsync(entitySet);
            }
            else
            {
                //原数据进行逻辑修改处理
                Update(entity, isLogical);
                //新数据复制到原数据
                entitySet.Adapt(entity, AdapterConfig);
                Update(entity);
                list.Add(entity);
                _dbSet.Update(entity);
            }
        }

        await SaveChangesAsync(isLogical);
        return list;
    }
    /// <summary>
    /// 删除记录
    /// </summary>
    /// <param name="id">业务数据主键</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task DeleteAsync(TKey id, bool isLogical = false)
    {
        var entitySet = await GetIfExistAsync(id);
        _logger.LogDebug("The user {user} will {isLogical} delete {typeName}, the content is: " + entitySet, UserName, GetLogicalString(isLogical), _typeName);

        base.Delete(entitySet, isLogical);
        await SaveChangesAsync(isLogical);
    }
    /// <summary>
    /// 批量删除记录
    /// </summary>
    /// <param name="ids">业务数据主键</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task DeletesAsync(IEnumerable<TKey> ids, bool isLogical = false)
    {
        var stringIds = ids.ToString(AppSettings.DEFAULT_SPLITER_STRING);
        _logger.LogDebug("The user {user} will {isLogical} deletes {typeName}, the ids are: " + stringIds, UserName, GetLogicalString(isLogical), _typeName);

        var entitySets = await GetQueryable(x => ids.Contains(x.Id)).ToListAsync();
        if (entitySets == null || entitySets.Any(x => !ids.Contains(x.Id)))
        {
            throw new BadHttpRequestException($"{typeof(TEntitySet).GetDisplayName()} 中当前记录不存在!");
        }

        foreach (var entitySet in entitySets)
        {
            base.Delete(entitySet, isLogical);
        }

        await SaveChangesAsync(isLogical);
    }
    /// <summary>
    /// 刷新缓存
    /// </summary>
    /// <returns></returns>
    public virtual async Task RefreshCacheAsync()
    {
        await base.RefreshCacheAsync<TEntitySet>();
        if (_localCache)
        {
            _logger.LogInformation("Type {typeName} has been changed, and will notice the client side to refresh cache", _typeName);
            await _communicator.RefreshCacheAsync(_type.Name);
        }
    }
    #endregion

    #region 重写基类方法
    /// <summary>
    /// 重载基类的新增方法, 完成自动业务数据及其视图模型的新增和保存
    /// </summary>
    /// <typeparam name="TModel">业务数据或其视图类型</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <returns></returns>
    public override async Task<TModel> AddAsync<TModel>(TModel model)
    {
        _logger.LogDebug("The user {user} will add {typeName}, the content is: " + model, UserName, typeof(TModel).GetDisplayName());
        if (model is IViewModel<TKey> viewModel)
        {
            await base.AddAsync(viewModel.Adapt<TEntitySet>(AdapterConfig));
        }
        else
        {
            await base.AddAsync(model);
        }

        await SaveChangesAsync<TModel>();
        return model;
    }
    /// <summary>
    /// 重载基类的修改方法, 完成自动业务数据及其视图模型的修改和保存
    /// </summary>
    /// <typeparam name="TModel">业务数据或其视图类型</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public override async Task<TModel> UpdateAsync<TModel>(TModel model, bool isLogical = false)
    {
        _logger.LogDebug("The user {user} will {isLogical} update {typeName}, the content is: " + model, UserName, GetLogicalString(isLogical), typeof(TModel).GetDisplayName());

        if (model is IViewModel<TKey> viewModel)
        {
            await base.UpdateAsync(viewModel.Adapt<TEntitySet>(AdapterConfig), isLogical);
        }
        else
        {
            await base.UpdateAsync(model, isLogical);
        }

        await SaveChangesAsync<TModel>(isLogical);
        return model;
    }
    /// <summary>
    /// 删除记录
    /// </summary>
    /// <param name="id">业务数据主键</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public override async Task DeleteAsync<TModel>(TKey id, bool isLogical = false)
    {
        _logger.LogDebug("The user {user} will {isLogical} update {typeName}, the content id is: " + id, UserName, GetLogicalString(isLogical), typeof(TModel).GetDisplayName());

        await base.DeleteAsync<TModel>(id, isLogical);
        await SaveChangesAsync<TModel>(isLogical);
    }
    /// <summary>
    /// 重载的刷新缓存方法, 刷新当前数据缓存
    /// </summary>
    /// <typeparam name="TModel"></typeparam>
    /// <returns></returns>
    public override async Task RefreshCacheAsync<TModel>()
    {
        await base.RefreshCacheAsync<TModel>();
        var type = typeof(TModel);
        if (type.GetAttributeValue<CacheableAttribute, bool>(nameof(CacheableAttribute.LocalCache)))
        {
            _logger.LogInformation("Type {typeName} has been changed, and will notice the client side to refresh cache", type.GetDisplayName());
            await _communicator.RefreshCacheAsync(type.Name);
        }
    }
    #endregion

    #region 重写的带业务附加信息的数据操作方法
    #region 新增部分
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息一并新增
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <returns></returns>
    public override async Task<TModel> AddAsync<TModel, TAdditional>(TModel model)
    {
        if (model is IViewModel<TKey> viewModel)
        {
            await AddAsync<TAdditional>(viewModel.Adapt<TEntitySet>(AdapterConfig));
        }
        else
        {
            await base.AddAsync<TModel, TAdditional>(model);
        }

        return model;
    }
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附件一并新增
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="attachments">附件</param>
    /// <returns></returns>
    public override async Task<TModel> AddAsync<TModel, TAttachment>(TModel model, IEnumerable<TAttachment>? attachments = default)
    {
        if (model is IViewModel<TKey> viewModel)
        {
            await AddAsync(viewModel.Adapt<TEntitySet>(AdapterConfig), attachments);
        }
        else
        {
            await base.AddAsync(model, attachments);
        }

        return model;
    }
    /// <summary>
    /// 此重载新增方法会同时将当前类型的某一种集合成员一并新增
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TElement">集合元素数据类型, 此时的集合是 IEntitySet</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="elements">业务数据引用数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    public override async Task<TModel> AddAsync<TModel, TElement>(TModel model, IEnumerable<TElement>? elements = default, string? foreignKey = default)
    {
        if (model is IViewModel<TKey> viewModel)
        {
            await AddAsync(viewModel.Adapt<TEntitySet>(AdapterConfig), elements, foreignKey);
        }
        else
        {
            await base.AddAsync(model, elements, foreignKey);
        }

        return model;
    }
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息及附件一并新增
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <returns></returns>
    public override async Task<TModel> AddAsync<TModel, TAdditional, TAttachment>(TModel model, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default)
    {
        if (model is IViewModel<TKey> viewModel)
        {
            await AddAsync(viewModel.Adapt<TEntitySet>(AdapterConfig), additionals, attachments);
        }
        else
        {
            await base.AddAsync(model, additionals, attachments);
        }
        return model;
    }
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息及集合元素数据一并新增
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    public override async Task<TModel> AddAsync<TModel, TAdditional, TElement>(TModel model, IEnumerable<TElement>? elements = default, string? foreignKey = default)
    {
        await AddAsync(ToEntitySet(model), elements, foreignKey);
        if (model is IViewModel<TKey> viewModel)
        {
            await AddAsync(viewModel.Adapt<TEntitySet>(AdapterConfig), elements, foreignKey);
        }
        else
        {
            await base.AddAsync(model, elements, foreignKey);
        }

        return model;
    }
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附件及集合元素数据一并新增
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="attachments">附件</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    public override async Task<TModel> AddAsync<TModel, TAttachment, TElement>(TModel model, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default)
    {
        if (model is IViewModel<TKey> viewModel)
        {
            await AddAsync(viewModel.Adapt<TEntitySet>(AdapterConfig), attachments, elements, foreignKey);
        }
        else
        {
            await base.AddAsync(model, attachments, elements, foreignKey);
        }

        return model;
    }
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息, 附件及集合元素数据一并新增
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    public override async Task<TModel> AddAsync<TModel, TAdditional, TAttachment, TElement>(TModel model, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default)
    {
        if (model is IViewModel<TKey> viewModel)
        {
            await AddAsync(viewModel.Adapt<TEntitySet>(AdapterConfig), additionals, attachments, elements, foreignKey);
        }
        else
        {
            await base.AddAsync(model, additionals, attachments, elements, foreignKey);
        }

        return model;
    }
    #endregion

    #region 修改部分
    /// <summary>
    /// 重载的更新方法会同时将当前类型的附加信息一并更新
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TAdditional">集合元素数据类型, 此时的集合是 IAdditional</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public override async Task<TModel> UpdateAsync<TModel, TAdditional>(TModel model, bool isLogical = false)
    {
        if (model is IViewModel<TKey> viewModel)
        {
            await UpdateAsync<TAdditional>(viewModel.Adapt<TEntitySet>(AdapterConfig), isLogical);
        }
        else
        {
            await base.UpdateAsync<TModel, TAdditional>(model, isLogical);
        }

        return model;
    }
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附件一并更新
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="attachments">附件</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public override async Task<TModel> UpdateAsync<TModel, TAttachment>(TModel model, IEnumerable<TAttachment>? attachments = default, bool isLogical = false)
    {
        if (model is IViewModel<TKey> viewModel)
        {
            await UpdateAsync(viewModel.Adapt<TEntitySet>(AdapterConfig), attachments, isLogical);
        }
        else
        {
            await base.UpdateAsync(model, attachments, isLogical);
        }

        return model;
    }
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public override async Task<TModel> UpdateAsync<TModel, TElement>(TModel model, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false)
    {
        if (model is IViewModel<TKey> viewModel)
        {
            await UpdateAsync(viewModel.Adapt<TEntitySet>(AdapterConfig), elements, foreignKey, isLogical);
        }
        else
        {
            await base.UpdateAsync(model, elements, foreignKey, isLogical);
        }

        return model;
    }
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附加信息及附件一并更新
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TAdditional">集合元素数据类型, 此时的集合是 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public override async Task<TModel> UpdateAsync<TModel, TAdditional, TAttachment>(TModel model, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default, bool isLogical = false)
    {
        if (model is IViewModel<TKey> viewModel)
        {
            await UpdateAsync(viewModel.Adapt<TEntitySet>(AdapterConfig), additionals, attachments, isLogical);
        }
        else
        {
            await base.UpdateAsync(model, additionals, attachments, isLogical);
        }

        return model;
    }
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附加信息及业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public override async Task<TModel> UpdateAsync<TModel, TAdditional, TElement>(TModel model, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false)
    {
        if (model is IViewModel<TKey> viewModel)
        {
            await UpdateAsync<TAdditional, TElement>(viewModel.Adapt<TEntitySet>(AdapterConfig), elements, foreignKey, isLogical);
        }
        else
        {
            await base.UpdateAsync<TModel, TAdditional, TElement>(model, elements, foreignKey, isLogical);
        }

        return model;
    }
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附件及业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="attachments"></param>
    /// <param name="elements"></param>
    /// <param name="foreignKey"></param>
    /// <param name="isLogical"></param>
    /// <returns></returns>
    public override async Task<TModel> UpdateAsync<TModel, TAttachment, TElement>(TModel model, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false)
    {
        if (model is IViewModel<TKey> viewModel)
        {
            await UpdateAsync(viewModel.Adapt<TEntitySet>(AdapterConfig), attachments, elements, foreignKey, isLogical);
        }
        else
        {
            await base.UpdateAsync(model, attachments, elements, foreignKey, isLogical);
        }

        return model;
    }
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附加信息, 附件及业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public override async Task<TModel> UpdateAsync<TModel, TAdditional, TAttachment, TElement>(TModel model, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false)
    {
        if (model is IViewModel<TKey> viewModel)
        {
            await UpdateAsync(viewModel.Adapt<TEntitySet>(AdapterConfig), additionals, attachments, elements, foreignKey, isLogical);
        }
        else
        {
            await base.UpdateAsync(model, additionals, attachments, elements, foreignKey, isLogical);
        }

        return model;
    }
    #endregion
    #endregion

    #region 带业务附加信息的数据操作方法
    #region 新增部分
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息一并新增
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> AddAsync<TAdditional>(TEntitySet entitySet) where TAdditional : class, IAdditional<TKey>
    {
        _logger.LogInformation("The user {user} will add {typeName} and it's additionals, the content is: " + entitySet, UserName, _typeName);

        await base.AddAsync(entitySet);
        await AddAdditionalsAsync<TAdditional>(entitySet, default);
        await SaveChangesAsync();
        return entitySet;
    }
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附件一并新增
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> AddAsync<TAttachment>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default) where TAttachment : class, IAttachment<TKey>
    {
        _logger.LogInformation("The user {user} will add {typeName} and it's attachments, the content is: " + entitySet, UserName, _typeName);

        await base.AddAsync(entitySet);
        await AddAttachmentsAsync(entitySet, attachments, default);
        await SaveChangesAsync();
        return entitySet;
    }
    /// <summary>
    /// 此重载新增方法会同时将当前类型的某一种集合成员一并新增
    /// </summary>
    /// <typeparam name="TElement">集合元素数据类型, 此时的集合是 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">业务数据引用数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> AddAsync<TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TElement : class, IEntitySet<TKey>
    {
        _logger.LogInformation("The user {user} will add {typeName} and it's related collection elements, the content is: " + entitySet, UserName, _typeName);

        await base.AddAsync(entitySet);
        await AddCollectionAsync(entitySet, elements, foreignKey);
        await SaveChangesAsync();
        return entitySet;
    }
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息及附件一并新增
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> AddAsync<TAdditional, TAttachment>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default) where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey>
    {
        _logger.LogInformation("The user {user} will add {typeName} and it's additionals, attachments, the content is: " + entitySet, UserName, _typeName);

        await base.AddAsync(entitySet);
        await AddAdditionalsAsync<TAdditional>(entitySet, default);
        await AddAttachmentsAsync(entitySet, attachments, default);
        await SaveChangesAsync();
        return entitySet;
    }
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息及集合元素数据一并新增
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> AddAsync<TAdditional, TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TAdditional : class, IAdditional<TKey> where TElement : class, IEntitySet<TKey>
    {
        _logger.LogInformation("The user {user} will add {typeName} and it's additionals, related collection elements, the content is: " + entitySet, UserName, _typeName);

        await base.AddAsync(entitySet);
        await AddAdditionalsAsync<TAdditional>(entitySet, default);
        await AddCollectionAsync(entitySet, elements, foreignKey);
        await SaveChangesAsync();
        return entitySet;
    }
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附件及集合元素数据一并新增
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> AddAsync<TAttachment, TElement>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>
    {
        _logger.LogInformation("The user {user} will add {typeName} and it's attachments, related collection elements, the content is: " + entitySet, UserName, _typeName);

        await base.AddAsync(entitySet);
        await AddAttachmentsAsync(entitySet, attachments, default);
        await AddCollectionAsync(entitySet, elements, foreignKey);
        await SaveChangesAsync();
        return entitySet;
    }
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息, 附件及集合元素数据一并新增
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> AddAsync<TAdditional, TAttachment, TElement>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>
    {
        _logger.LogInformation("The user {user} will add {typeName} and it's additionals, attachments, related collection elements, the content is: " + entitySet, UserName, _typeName);

        await base.AddAsync(entitySet);
        await AddAdditionalsAsync<TAdditional>(entitySet, default);
        await AddAttachmentsAsync(entitySet, attachments, default);
        await AddCollectionAsync(entitySet, elements, foreignKey);
        await SaveChangesAsync();
        return entitySet;
    }
    #endregion

    #region 修改部分
    /// <summary>
    /// 重载的更新方法会同时将当前类型的附加信息一并更新
    /// </summary>
    /// <typeparam name="TAdditional">集合元素数据类型, 此时的集合是 IAdditional</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> UpdateAsync<TAdditional>(TEntitySet entitySet, bool isLogical = false) where TAdditional : class, IAdditional<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} update {typeName} and it's additionals, the content is: " + entitySet, UserName, GetLogicalString(isLogical), _typeName);

        await base.UpdateAsync(entitySet, isLogical);
        await UpdateAdditionalsAsync<TAdditional>(entitySet, default, isLogical);
        await SaveChangesAsync(isLogical);
        return entitySet;
    }
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附件一并更新
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> UpdateAsync<TAttachment>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, bool isLogical = false) where TAttachment : class, IAttachment<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} update {typeName} and it's attachments, the content is: " + entitySet, UserName, GetLogicalString(isLogical), _typeName);

        await base.UpdateAsync(entitySet, isLogical);
        var files = await UpdateAttachmentsAsync(entitySet, attachments, default, isLogical);
        await SaveChangesAndDeleteFilesAsync(isLogical, files);
        return entitySet;
    }
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> UpdateAsync<TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TElement : class, IEntitySet<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} update {typeName} and it's related collection elements, the content is: " + entitySet, UserName, GetLogicalString(isLogical), _typeName);

        await base.UpdateAsync(entitySet, isLogical);
        await UpdateCollectionAsync(entitySet, elements, foreignKey, isLogical);
        await SaveChangesAsync(isLogical);
        return entitySet;
    }
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附加信息及附件一并更新
    /// </summary>
    /// <typeparam name="TAdditional">集合元素数据类型, 此时的集合是 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> UpdateAsync<TAdditional, TAttachment>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} update {typeName} and it's additionals, attachments, the content is: " + entitySet, UserName, GetLogicalString(isLogical), _typeName);

        await base.UpdateAsync(entitySet, isLogical);
        await UpdateAdditionalsAsync<TAdditional>(entitySet, default, isLogical);
        var files = await UpdateAttachmentsAsync(entitySet, attachments, default, isLogical);
        await SaveChangesAndDeleteFilesAsync(isLogical, files);
        return entitySet;
    }
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附加信息及业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> UpdateAsync<TAdditional, TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey> where TElement : class, IEntitySet<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} update {typeName} and it's additionals, related collection elements, the content is: " + entitySet, UserName, GetLogicalString(isLogical), _typeName);

        await base.UpdateAsync(entitySet, isLogical);
        await UpdateAdditionalsAsync<TAdditional>(entitySet, default, isLogical);
        await UpdateCollectionAsync(entitySet, elements, foreignKey, isLogical);
        await SaveChangesAsync(isLogical);
        return entitySet;
    }
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附件及业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet"></param>
    /// <param name="attachments"></param>
    /// <param name="elements"></param>
    /// <param name="foreignKey"></param>
    /// <param name="isLogical"></param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> UpdateAsync<TAttachment, TElement>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} update {typeName} and it's attachments, related collection elements, the content is: " + entitySet, UserName, GetLogicalString(isLogical), _typeName);

        await base.UpdateAsync(entitySet, isLogical);
        var files = await UpdateAttachmentsAsync(entitySet, attachments, default, isLogical);
        await UpdateCollectionAsync(entitySet, elements, foreignKey, isLogical);
        await SaveChangesAndDeleteFilesAsync(isLogical, files);
        return entitySet;
    }
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附加信息, 附件及业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task<TEntitySet> UpdateAsync<TAdditional, TAttachment, TElement>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} update {typeName} and it's additionals, attachments, related collection elements, the content is: " + entitySet, UserName, GetLogicalString(isLogical), _typeName);

        await base.UpdateAsync(entitySet, isLogical);
        await UpdateAdditionalsAsync<TAdditional>(entitySet, default, isLogical);
        var files = await UpdateAttachmentsAsync(entitySet, attachments, default, isLogical);
        await UpdateCollectionAsync(entitySet, elements, foreignKey, isLogical);
        await SaveChangesAndDeleteFilesAsync(isLogical, files);
        return entitySet;
    }
    #endregion

    #region 删除部分
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附加信息一并删除
    /// </summary>
    /// <typeparam name="TAdditional">集合元素数据类型, 此时的集合是 IAdditional</typeparam>
    /// <param name="additionalId">业务数据主键</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task DeleteAsync<TAdditional>(TKey additionalId, IEnumerable<TAdditional>? additionals = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} delete {typeName} and it's additionals, the content id is: " + additionalId, UserName, GetLogicalString(isLogical), _typeName);

        await DeleteAdditionalsAsync(additionalId, additionals, isLogical);
        await base.DeleteAsync<TEntitySet>(additionalId, isLogical);
        await SaveChangesAsync(isLogical);
    }
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附件一并删除
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="businessKey">业务主键</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task DeleteAsync<TAttachment>(TKey businessKey, string? businessType = default, bool isLogical = false) where TAttachment : class, IAttachment<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} delete {typeName} and it's attachments, the content id is: " + businessKey, UserName, GetLogicalString(isLogical), _typeName);

        var files = await DeleteAttachmentsAsync<TAttachment>(businessKey, businessType, isLogical);
        await base.DeleteAsync<TEntitySet>(businessKey, isLogical);
        await SaveChangesAndDeleteFilesAsync(isLogical, files);
    }
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据引用的数据集合一并删除
    /// </summary>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task DeleteAsync<TElement>(TKey id, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TElement : class, IEntitySet<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} delete {typeName} and it's related collection elements, the content id is: " + id, UserName, GetLogicalString(isLogical), _typeName);

        await DeleteCollectionAsync(id, elements, foreignKey, isLogical);
        await base.DeleteAsync<TEntitySet>(id, isLogical);
        await SaveChangesAsync(isLogical);
    }
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附加信息及附件一并删除
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task DeleteAsync<TAdditional, TAttachment>(TKey id, IEnumerable<TAdditional>? additionals = default, string? businessType = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} delete {typeName} and it's additionals, attachments, the content id is: " + id, UserName, GetLogicalString(isLogical), _typeName);

        await DeleteAdditionalsAsync<TAdditional>(id, default, isLogical);
        var files = await DeleteAttachmentsAsync<TAttachment>(id, businessType, isLogical);
        await base.DeleteAsync<TEntitySet>(id, isLogical);
        await SaveChangesAndDeleteFilesAsync(isLogical, files);
    }
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附加信息及业务数据引用的数据集合一并删除
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task DeleteAsync<TAdditional, TElement>(TKey id, IEnumerable<TAdditional>? additionals = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey> where TElement : class, IEntitySet<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} delete {typeName} and it's additionals, related collection elements, the content id is: " + id, UserName, GetLogicalString(isLogical), _typeName);

        await DeleteAdditionalsAsync<TAdditional>(id, default, isLogical);
        await DeleteCollectionAsync(id, elements, foreignKey, isLogical);
        await base.DeleteAsync<TEntitySet>(id, isLogical);
        await SaveChangesAsync(isLogical);
    }
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附件及业务数据引用的数据集合一并删除
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task DeleteAsync<TAttachment, TElement>(TKey id, string? businessType = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} delete {typeName} and it's attachments, related collection elements, the content id is: " + id, UserName, GetLogicalString(isLogical), _typeName);

        var files = await DeleteAttachmentsAsync<TAttachment>(id, businessType, isLogical);
        await DeleteCollectionAsync(id, elements, foreignKey, isLogical);
        await base.DeleteAsync<TEntitySet>(id, isLogical);
        await SaveChangesAndDeleteFilesAsync(isLogical, files);
    }
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附加信息, 附件及业务数据引用的数据集合一并删除
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task DeleteAsync<TAdditional, TAttachment, TElement>(TKey id, IEnumerable<TAdditional>? additionals = default, string? businessType = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>
    {
        _logger.LogDebug("The user {user} will {isLogical} delete {typeName} and it's additionals, attachments, related collection elements, the content id is: " + id, UserName, GetLogicalString(isLogical), _typeName);

        await DeleteAdditionalsAsync<TAdditional>(id, default, isLogical);
        var files = await DeleteAttachmentsAsync<TAttachment>(id, businessType, isLogical);
        await DeleteCollectionAsync(id, elements, foreignKey, isLogical);
        await base.DeleteAsync<TEntitySet>(id, isLogical);
        await SaveChangesAndDeleteFilesAsync(isLogical, files);
    }
    #endregion
    #endregion

    #region 业务附加信息类操作方法
    /// <summary>
    /// 新增业务数据的附加信息
    /// </summary>
    /// <typeparam name="TAdditional">集合元素数据类型, 此时的集合是 IAdditional</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <returns></returns>
    public virtual async Task AddAdditionalsAsync<TAdditional>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default) where TAdditional : class, IAdditional<TKey> => await base.AddAdditionalsAsync(entitySet, additionals);
    /// <summary>
    /// 更新业务数据的附加信息
    /// </summary>
    /// <typeparam name="TAdditional">集合元素数据类型, 此时的集合是 IAdditional</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task UpdateAdditionalsAsync<TAdditional>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey> => await base.UpdateAdditionalsAsync(entitySet, additionals, isLogical);
    #endregion

    #region 业务数据引用关系的集合类操作方法
    /// <summary>
    /// 新增业务数据对象中 TElement 类型的集合对象
    /// </summary>
    /// <typeparam name="TElement">集合元素数据类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">引用数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    public virtual async Task AddCollectionAsync<TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TElement : class, IEntitySet<TKey> => await base.AddCollectionAsync(entitySet, elements, foreignKey);
    /// <summary>
    /// 更新业务数据对象中 TElement 类型的集合对象
    /// </summary>
    /// <typeparam name="TElement">集合元素数据类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">引用数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task UpdateCollectionAsync<TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TElement : class, IEntitySet<TKey> => await base.UpdateCollectionAsync(entitySet, elements, foreignKey, isLogical);
    /// <summary>
    /// 删除业务数据对象中 TElement 类型的集合对象
    /// </summary>
    /// <typeparam name="TElement">集合元素数据类型</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="elements">引用数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    public virtual async Task DeleteCollectionAsync<TElement>(TKey id, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TElement : class, IEntitySet<TKey> => await base.DeleteCollectionAsync<TEntitySet, TElement>(id, elements, foreignKey, isLogical);
    #endregion

    #region 文件及业务数据附件操作方法
    /// <summary>
    /// 新增附件
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件集合</param>
    /// <param name="businessType">业务类型</param>
    /// <returns>待删除文件列表, 请在数据库事物提交成功后删除列表中的文件</returns>
    public virtual async Task AddAttachmentsAsync<TAttachment>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, string? businessType = default) where TAttachment : class, IAttachment<TKey> => await base.AddAttachmentsAsync(entitySet, attachments, businessType);
    /// <summary>
    /// 修改附件, 保留旧附件, 新增新附件, 返回待删除文件列表
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件集合</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns>待删除文件列表, 请在数据库事物提交成功后删除列表中的文件</returns>
    public virtual async Task<IEnumerable<string>> UpdateAttachmentsAsync<TAttachment>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, string? businessType = default, bool isLogical = false) where TAttachment : class, IAttachment<TKey> => await base.UpdateAttachmentsAsync(entitySet, attachments, businessType, isLogical);
    #endregion

    #region 内部成员方法
    /// <summary>
    /// 提交当前操作的内部包装方法, 包含判断是否自动提交
    /// </summary>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    protected virtual async Task<int> SaveChangesAsync(bool isLogical = false)
    {
        if (AutoSaveChanges)
        {
            var result = await base.SaveChangesAsync();
            if (result > 0)
            {
                _logger.LogInformation("The user {user} save change {typeName} to database success {isLogical}", UserName, _typeName, GetLogicalString(isLogical));
                await RefreshCacheAsync();
            }

            return result;
        }

        return 0;
    }
    /// <summary>
    /// 提交当前操作的内部包装方法, 包含判断是否自动提交, 以及删除附件
    /// </summary>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <param name="files">待删除的文件</param>
    /// <returns></returns>
    protected virtual async Task<int> SaveChangesAndDeleteFilesAsync(bool isLogical = false, IEnumerable<string>? files = null)
    {
        if (AutoSaveChanges)
        {
            var result = await base.SaveChangesAsync();
            if (result > 0)
            {
                _logger.LogInformation("The user {user} save change {typeName} to database success {isLogical}", UserName, _typeName, GetLogicalString(isLogical));
                await RefreshCacheAsync();
                if (files != null && files.Any())
                {
                    Delete(files);
                }
            }

            return result;
        }

        return 0;
    }
    /// <summary>
    /// 获取第一个 BusinessType 特性标记的属性的 BusinessType Name
    /// 返回 BusinessType 的值
    /// </summary>
    /// <returns></returns>
    protected virtual string GetBusinessType()
    {
        var type = typeof(TEntitySet);
        var businessType = type.Name;
        var propertyInfo = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(x => x.HasAttribute<BusinessTypeAttribute>());
        if (propertyInfo != null)
        {
            businessType = propertyInfo.GetAttributeValue<BusinessTypeAttribute, string>(nameof(BusinessTypeAttribute.Name));
            businessType ??= type.Name + AppSettings.CHAR_DOT + propertyInfo.Name;
        }

        return businessType;
    }
    /// <summary>
    /// 获取全部 BusinessType 特性标记的属性的 BusinessType Name 集合
    /// 返回属性 和 BusinessType 的值的集合
    /// </summary>
    /// <returns></returns>
    protected virtual IEnumerable<KeyValuePair<string, string>> GetBusinessTypes()
    {
        var type = typeof(TEntitySet);
        var dic = new Dictionary<string, string>();
        var propertyInfos = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.HasAttribute<BusinessTypeAttribute>());
        if (propertyInfos != null && propertyInfos.Any())
        {
            foreach (var propertyInfo in propertyInfos)
            {
                var businessType = propertyInfo.GetAttributeValue<BusinessTypeAttribute, string>(nameof(BusinessTypeAttribute.Name));
                businessType ??= type.Name + AppSettings.CHAR_DOT + propertyInfo.Name;
                dic.Add(propertyInfo.Name, businessType);
            }
        }

        return dic;
    }
    /// <summary>
    /// 获取可用外键名或者抛出异常
    /// </summary>
    /// <typeparam name="TElement">集合元素数据类型</typeparam>
    /// <param name="foreignKey">业务类型对于 TElement 类型的外键</param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    protected virtual string GetForeignKey<TElement>(string? foreignKey = default)
    {
        foreignKey ??= typeof(TElement).GetForeignKey<TEntitySet, TKey>();
        if (string.IsNullOrWhiteSpace(foreignKey))
        {
            throw new ArgumentNullException(nameof(foreignKey), "foreign key can't be null!");
        }

        return foreignKey;
    }
    /// <summary>
    /// 视图模型转换为业务数据对象模型
    /// </summary>
    /// <typeparam name="TModel">业务数据类型或其视图类型</typeparam>
    /// <param name="model">业务数据或其视图</param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    protected virtual TEntitySet ToEntitySet<TModel>(TModel model) => base.ToEntitySet<TEntitySet, TModel>(model);
    #endregion
}

/// <summary>
/// 公共数据处理服务
/// 字符串作为键的默认实现
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
/// <typeparam name="TEntitySet">业务数据类型</typeparam>
public class DataService<TDbContext, TEntitySet> :
    DataService<TDbContext, TEntitySet, string>,
    IDataService<TDbContext, TEntitySet>
    where TDbContext : DbContext
    where TEntitySet : class, IEntitySet<string>
{
    public DataService(
        TDbContext context,
        ILogger<DataService<TDbContext, TEntitySet>> logger,
        IDistributedCache cache,
        IHttpContextAccessor httpContextAccessor,
        IMessageCommunicator communicator,
        AppSetting appSetting
        ) : base(context, logger, cache, httpContextAccessor, communicator, appSetting) { }
}